////////////////////////////////////////////////////////////////////////////////
// Copyright 2006 CORE Solutions Limited
// All rights reserved.
// PROPRIETARY AND CONFIDENTIAL INFORMATION.
// Use is subject to license terms.
//
// FUNCTION ID      :   CustomTextTag.java
// AUTHOR           :   Ric Yik
// DATE CREATE      :   2006/4/6
// DESCRIPTION      :
//                  :
//                  :
//                  :
//
// MODIFICATION HISTORY:
// DATE         AUTHOR          VERSION NO.         COMMENT
// -----------  --------------  ------------------  -------------------
// 2006/04/06   Ric Yik         1.0                 source is created.
// 2006/04/26   Ric Yik         1.0                 BugZilla #5535
//
//
////////////////////////////////////////////////////////////////////////////////

package com.erp.framework.controller.taglib;

import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.StringTokenizer;

import javax.servlet.jsp.JspException;

import org.apache.struts.taglib.html.Constants;
import org.apache.struts.taglib.html.TextTag;
import org.apache.struts.util.BeanUtils;
import org.apache.struts.util.IteratorAdapter;
import org.apache.struts.util.PropertyUtils;
import org.apache.struts.util.RequestUtils;
import org.apache.struts.util.ResponseUtils;

import com.erp.app.common.ProjectConstants;
import com.erp.app.common.util.MapIterator;
import com.erp.app.util.web.WebUtil;
import com.erp.framework.SimpleConstants;
import com.erp.framework.controller.form.FieldUIControl;
import com.erp.framework.controller.form.MultiRow;
import com.erp.framework.controller.form.SimpleCoreForm;
import com.erp.framework.controller.form.SimpleMaintStyleForm;
import com.erp.framework.controller.form.UIControlInterceptor;
import com.erp.framework.model.schema.MetaData;
import com.erp.framework.model.schema.TableSchema;
import com.erp.framework.model.vo.SimpleBaseVo;
import com.erp.framework.util.BeanUtil;
import com.erp.framework.util.CommonUtil;
import com.erp.framework.util.apaches.commons.collection.map.LinkedMap;
import com.erp.framework.util.logger.Logger;

public class CustomTextTag extends TextTag implements FieldUIControl {

    public CustomTextTag() {
        super();
        this.reset();
    }

    /**
     * Indicates if exteneded features are used. Default to false
     */
    private boolean useExtensions;

    /**
     * The type of the UI to be rendered. Default to SimpleConstants.UI_TYPE_TEXT
     */
    private String uiType;

    private String childTsIndex;

    private String visibility;

    private String showEmpty = "true";

    private boolean showCode = true;
    private boolean showCodeSet = true;

    private boolean showDescription = true;

    private String actionURL;

    private String idx;

    private int decimalPlaces = -1;

    private boolean calendarImgFlag = true;
    private String calendarImgUrl = "images/date.gif";
    
    private boolean showGuideInfo = false;

    public boolean isShowGuideInfo() {
		return showGuideInfo;
	}

	public void setShowGuideInfo(boolean showGuideInfo) {
		this.showGuideInfo = showGuideInfo;
	}

	public String getIdx() {
        return idx;
    }

    public void setIdx(String idx) {
        this.idx = idx;
    }

    public boolean getShowCode() {
        return showCode;
    }

    public void setShowCode(boolean showCode) {
        this.showCode = showCode;
        this.setShowCodeSet(true);
    }

    public boolean getShowDescription() {
        return showDescription;
    }

    public void setShowDescription(boolean showDescription) {
        this.showDescription = showDescription;
    }

    /**
     * Filter the rendered output for characters that are sensitive in HTML?
     */

    public boolean getUseExtensions() {
        return useExtensions;
    }

    public void setUseExtensions(boolean useExtensions) {
        this.useExtensions = useExtensions;
    }

    /**
     * @see com.erp.framework.controller.form.FieldUIControl#getUiType()
     */
    public String getUiType() {
        return uiType;
    }

    /**
     * @see com.erp.framework.controller.form.FieldUIControl#setUiType(java.lang.String)
     */
    public void setUiType(String uiType) {
        this.uiType = uiType;
    }

    /**
     * @see com.erp.framework.controller.form.FieldUIControl#getChildTsIndex()
     */
    public String getChildTsIndex() {
        return childTsIndex;
    }

    /**
     * @see com.erp.framework.controller.form.FieldUIControl#setChildTsIndex(java.lang.String)
     */
    public void setChildTsIndex(String childTsIndex) {
        this.childTsIndex = childTsIndex;
    }

    /**
     * Filter the rendered output for characters that are sensitive in HTML?
     */
    protected boolean filter = true;

    /**
     * @see com.erp.framework.controller.form.FieldUIControl#getFilter()
     */
    public boolean getFilter() {
        return (this.filter);
    }

    /**
     * @see com.erp.framework.controller.form.FieldUIControl#setFilter(boolean)
     */
    public void setFilter(boolean filter) {
        this.filter = filter;
    }

    public String getVisibility() {
        return visibility;
    }

    public void setVisibility(String visibility) {
        this.visibility = visibility;
    }

    public String getShowEmpty() {
		return showEmpty;
	}

	public void setShowEmpty(String showEmpty) {
		this.showEmpty = showEmpty;
	}

	public String getActionURL() {
        return actionURL;
    }

    public void setActionURL(String actionURL) {
        this.actionURL = actionURL;
    }

    public int getDecimalPlaces() {
        return decimalPlaces;
    }

    public void setDecimalPlaces(int decimalPlaces) {
        this.decimalPlaces = decimalPlaces;
    }

    protected void reset() {
        this.setUseExtensions(false);
        this.setUiType(SimpleConstants.UI_TYPE_TEXT);
        this.setCols(null);
        this.setRows(null);
        this.setName(Constants.BEAN_KEY);
        this.setFilter(true);
        this.setChildTsIndex(null);
        this.setVisibility(SimpleConstants.UI_VISIBILITY_EDITABLE);
        this.setShowEmpty("true");
        this.setShowCode(true);
        this.setShowCodeSet(false);
        this.setShowDescription(true);
        this.setActionURL(null);
        this.setIdx(null);
        this.setDecimalPlaces(-1);
        super.release();
    }

    public boolean isTextArea() {
        return SimpleConstants.UI_TYPE_TEXTAREA.equalsIgnoreCase(this.getUiType());
    }

    public boolean isText() {
        return SimpleConstants.UI_TYPE_TEXT.equalsIgnoreCase(this.getUiType());
    }

    public boolean isLabel() {
        return SimpleConstants.UI_TYPE_LABEL.equalsIgnoreCase(this.getUiType());
    }

    public boolean isComboBox() {
        return SimpleConstants.UI_TYPE_COMBOBOX.equalsIgnoreCase(this.getUiType());
    }

    public boolean isWrite() {
        return SimpleConstants.UI_TYPE_WRITE.equalsIgnoreCase(this.getUiType());
    }

    public boolean isDisplayOnly() {
        return SimpleConstants.UI_VISIBILITY_DISPLAYONLY.equalsIgnoreCase(this.getVisibility());
    }

    public boolean isHidden() {
        return SimpleConstants.UI_VISIBILITY_HIDDEN.equalsIgnoreCase(this.getVisibility());
    }

    public boolean isImage() {
        return SimpleConstants.UI_TYPE_IMAGE.equalsIgnoreCase(this.getUiType());
    }

    public int doStartTag() throws JspException {
        int result = -1;
        if (this.getUseExtensions()) {
            Object object = pageContext.findAttribute(this.getName());
            Object form = pageContext.findAttribute(Constants.BEAN_KEY);
            if (form == null) {
                Logger.debug(this, "form is null.");
                return SKIP_BODY;
            }
            String childTsIndex = this.getChildTsIndex();
            if ("current".equals(childTsIndex)) {
                childTsIndex = (object instanceof SimpleMaintStyleForm) ? String.valueOf(((SimpleMaintStyleForm) object).getCurrIdx()) : "";
            } else if (!CommonUtil.isValidPositiveIntegerOrZero(childTsIndex) && !CommonUtil.isEmpty(childTsIndex)) {
                throw new JspException("Invalid value for the optional attribute childTsIndex: must be either \"current\", any non-negative integer, or an empty string.");
            }
            TableSchema ts = WebUtil.findTs(object, (SimpleCoreForm) form, childTsIndex);
            MetaData metadata = null;
            if (ts != null) {
                metadata = ts.getMetaDataByVoName(this.getProperty());
                if (metadata == null) {
                    try {
                        this.setProperty(TagLibUtil.resolveVariableBindings(pageContext, this.getProperty()));
                        metadata = BeanUtil.getMetaData((object instanceof SimpleBaseVo) ? form : object, this.getProperty());
                    } catch (Exception e) {
                        Logger.logExceptions(this, e);
                    }
                }
                if (metadata == null) {
                    Logger.debug(this, "metadata is null - name = \"" + this.getName() + "\", property = \"" + this.getProperty() + "\"");
                }
            } else {
                Logger.debug(this, "ts is null - name = \"" + this.getName() + "\", property = \"" + this.getProperty() + "\"");
            }
            if (this.isTextArea() && metadata != null) {
                this.setCols(String.valueOf(metadata.getTextAreaColSize()));
                this.setRows(String.valueOf(metadata.getTextAreaRowSize()));
            }

            if (form instanceof UIControlInterceptor) {
                try {
                    ((UIControlInterceptor) form).beforeRenderField(object, metadata, this);
                } catch (Exception e) {
                    Logger.logExceptions(form, e);
                }
            }

//            if (metadata != null && metadata.containsStereoType(StereoType.USER)) {
//                if (!this.isLabel()) {
//                    if (this.isWrite()) {
//                        this.setVisibility(SimpleConstants.UI_VISIBILITY_DISPLAYONLY);
//                    }
//                    this.setUiType(SimpleConstants.UI_TYPE_COMBOBOX);
//                }
//            }

            // Emit HTML
            if (this.isTextArea()) {
                if (CommonUtil.isEmpty(this.getStyleClass())) {
                    this.setStyleClass("textarea1");
                }
                result = this.doTextareaStartTag(object, metadata);
                this.reset();
                return result;
            } else if (this.isLabel()) {
                result = this.doLabelStartTag(object, metadata);
                this.reset();
                return result;
            } else if (this.isComboBox()) {
                if (CommonUtil.isEmpty(this.getStyleClass())) {
                    this.setStyleClass("selectbox1");
                }
                result = this.doComboBoxStartTag(object, metadata);
                this.reset();
                return result;
            } else if (this.isImage()) {
                result = this.doImageStartTag(object, metadata);
                this.reset();
                return result;
            } else {
                // Handle Numbers: Solutions from Edal
                if (this.getUseExtensions()) {
                    if (metadata != null && metadata.isAmount() && !this.isDisplayOnly()) this.setStyleClass("number");
                }
                if ("number".equals(this.getStyleClass())) this.setOnblur("doAddCommas(this);" + CommonUtil.nullToString(this.getOnblur()));
                if (this.isText()) {
                    if (metadata != null) {
                        int size = metadata.getDisplaySize();
                        int maxLength = metadata.getColumnSize();
                        try {
                            Class propertyClass = Class.forName(metadata.getColumnClassName());
                            if (Date.class.isAssignableFrom(propertyClass)) {
                                maxLength = SimpleConstants.INPUT_DATE_LENGTH;
                            }
                        } catch (ClassNotFoundException e) {
                            Logger.log(metadata, e.getMessage());
                        }
                        this.setSize(String.valueOf(size));
                        this.setMaxlength(String.valueOf(maxLength));
                    }
                    if (CommonUtil.isEmpty(this.getStyleClass())) {
                        this.setStyleClass("textbox1");
                    }
                    result = this.doTextStartTag(object, metadata);
                    this.reset();
                    return result;
                } else {
                    result = this.doWriteStartTag(object, metadata);
                    this.reset();
                    return result;
                }
            }
        } else {
            result = super.doStartTag();
            this.reset();
            return result;
        }
    }

    protected void prepareEventHandler(String property) {
        String eventHandler = CommonUtil.getString(BeanUtil.getPropertyDefault(this, property));
        StringTokenizer tokens = new StringTokenizer(eventHandler);
        if (tokens.hasMoreTokens()) {
            if ("pageEvent".equals(tokens.nextToken(":"))) {
                if (tokens.hasMoreTokens()) {
                    BeanUtil.setPropertyDefault(this, property, this.toDoSubmitEventHandler(tokens.nextToken()));
                }
            }
        }
    }

    protected String prepareEventHandlers() {
        this.prepareEventHandler("onchange");
        return super.prepareEventHandlers();
    }

    protected int doImageStartTag(Object object, MetaData metadata) throws JspException {

        Object image = BeanUtil.getPropertyDefault(object, this.getProperty());
        String childTsIndex = this.getChildTsIndex();
        if ("current".equals(childTsIndex)) {
            Object form = pageContext.findAttribute(Constants.BEAN_KEY);
            childTsIndex = (form instanceof SimpleMaintStyleForm) ? String.valueOf(((SimpleMaintStyleForm) form).getCurrIdx()) : "";
        } else if (!CommonUtil.isValidPositiveIntegerOrZero(childTsIndex) && !CommonUtil.isEmpty(childTsIndex)) {
            throw new JspException("Invalid value for the optional attribute childTsIndex: must be either \"current\", any non-negative integer, or an empty string.");
        }
        StringBuffer results = new StringBuffer();
        String contentType = CommonUtil.getString(BeanUtil.getPropertyDefault(object, metadata.getContentTypeProperty()));
        if ((image != null)&&(!"".equals(contentType))) {

            if (contentType.startsWith("image")) {
            	String width = CommonUtil.getString(BeanUtil.getPropertyDefault(object, metadata.getImageWidthProperty()));
                String height = CommonUtil.getString(BeanUtil.getPropertyDefault(object, metadata.getImageHeightProperty()));
                if (!CommonUtil.isEmpty(width)) width = "width =\"" + width  + "\"";
                if (CommonUtil.isEmpty(height)) height = "300";
                height = "height =\"" + height  + "\"";
                String imageProperty = this.getProperty();
                if (!CommonUtil.isEmpty(metadata.getImageThumbnailProperty())) {
                    imageProperty = metadata.getImageThumbnailProperty();
                    byte[] thumbnail = (byte[]) BeanUtil.getPropertyDefault(object, metadata.getImageThumbnailProperty());
                    if (thumbnail == null) {
                        thumbnail = (byte []) image;
//                        try {
//                            Image itemImage = Image.getInstance(thumbnail);
//                            float maxHeight = 300.0f;
//                            float maxWidth = 300.0f;
//                            float pHeight = itemImage.plainHeight();
//                            float pWidth = itemImage.plainWidth();
//                            if (pHeight > maxHeight || pWidth > maxWidth) {
//                                itemImage.scaleToFit(maxWidth, maxHeight);
//                            }
//                            pHeight = itemImage.plainHeight();
//                            pWidth = itemImage.plainWidth();
//                            width = "width=\"" + (int) pWidth + "\"";
//                            height = "height=\"" + (int) pHeight + "\"";
//                        } catch (BadElementException e) {
//                            e.printStackTrace();
//                        } catch (MalformedURLException e) {
//                            e.printStackTrace();
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
                    }
                }
                results.append("<img src=\"" + this.getActionURL()  + "?pageEvent=getAttachment&currIdx=" + childTsIndex + "&idx=" + this.getIdx() + "&imageProperty=" + imageProperty + "\" " + width + " " + height + " ");
                results.append(prepareEventHandlers());
                results.append(prepareStyles());
                results.append("/>");
                /* results.append("<input name=\"" + this.getProperty() + "ViewButton\" type=\"button\" onclick=\"javascript:window.open(\'"+this.getActionURL()+ "?pageEvent=viewAttach&currIdx=" + childTsIndex + "&idx=" + this.getIdx() + "&imageProperty=" + this.getProperty()+"',\'view\'"
                		+",\'toolbar=no,scrollbars=1,resizable=1,statusbar=no,menubar=no,width=640,height=400,top=0,left=0\');\"" +  " class=\"button1\" value=\"View\" />");*/

            } else {
                results.append("<input name=\"" + this.getProperty() + "DownloadButton\" type=\"button\" onclick=\"location.href='" + this.getActionURL()  + "?pageEvent=getAttachment&currIdx=" + childTsIndex + "&idx=" + this.getIdx() + "&imageProperty=" + this.getProperty() + "&download=" + SimpleConstants.GENERIC_YES + "'\" class=\"button1\" value=\"Download\" />");

            }
            results.append("<input name=\"" + this.getProperty() + "DeleteButton\" type=\"button\" onclick=\"location.href='" + this.getActionURL()  + "?pageEvent=delAttach&currIdx=" + childTsIndex + "&idx=" + this.getIdx() + "&imageProperty=" + this.getProperty() + "'\" class=\"button1\" value=\"Del\" />");
            ResponseUtils.write(pageContext, results.toString());
        }else {
        	results.append("<input name=\"" + this.getProperty() + "AddButton\" type=\"button\" onclick=\"location.href='" + this.getActionURL()  + "?pageEvent=addAttach&currIdx=" + childTsIndex + "&idx=" + this.getIdx() + "&imageProperty=" + this.getProperty() + "'\" class=\"button1\" value=\"Add\" />");
        	ResponseUtils.write(pageContext, results.toString());
        }
        return (SKIP_BODY);
    }

    protected int doComboBoxStartTag(Object object, MetaData metadata) throws JspException {
        StringBuffer results = new StringBuffer("");
        if (!this.isDisplayOnly()) {
            this.setStyleClass("selectBox1");
            results.append("<select");
            results.append(" name=\"");
            results.append(property);
            results.append("\"");
            if (accesskey != null) {
                results.append(" accesskey=\"");
                results.append(accesskey);
                results.append("\"");
            }
            if (tabindex != null) {
                results.append(" tabindex=\"");
                results.append(tabindex);
                results.append("\"");
            }
            if (this.getReadonly() || this.getDisabled()) {
                results.append(" disabled=\"");
                results.append(this.getDisabled());
                results.append("\"");
            }
            results.append(prepareEventHandlers());
            results.append(prepareStyles());
            results.append(">");
            ResponseUtils.write(pageContext, results.toString());
        }
        this.doOptions(object, metadata);
        if (!this.isDisplayOnly()) {
            ResponseUtils.write(pageContext, "</select>");
        }
        return (SKIP_BODY);
    }

    public int doOptions(Object object, MetaData metadata) throws JspException {
        StringBuffer sb = new StringBuffer();
        String property = "key";
        String labelProperty = "value";
        if(CommonUtil.nullToString(this.getShowEmpty()).equals("true")){
        	addOption(sb, "", "", false); // Add an empty option
        }
        String collection = this.getProperty();
        Iterator collIterator = getIterator(this.getName(), collection);
        if (collIterator instanceof MapIterator) {
            // Optmization for MapIterator
            Map map = ((MapIterator) collIterator).getMap();
            Object value = BeanUtil.getPropertyDefault(object, this.getProperty());
            Object label = (map.containsKey(value)) ? map.get(value) : (CommonUtil.isEmpty(value)) ? value : "(Code not found)";
            if (!map.containsKey(value) && !CommonUtil.isEmpty(value)) {
                this.setShowCode(true);
                this.setShowDescription(true);
                addOption(sb, CommonUtil.getString(value), CommonUtil.getString(label), true);
            }
        }
        while (collIterator.hasNext()) {

            Object bean = collIterator.next();
            Object value = null;
            Object label = null;

            try {
                value = PropertyUtils.getProperty(bean, property);
                if (value == null)
                    value = "";
            } catch (IllegalAccessException e) {
                throw new JspException(messages.getMessage("getter.access", property, bean));
            } catch (InvocationTargetException e) {
                Throwable t = e.getTargetException();
                throw new JspException(messages.getMessage("getter.result", property, t.toString()));
            } catch (NoSuchMethodException e) {
                throw new JspException(messages.getMessage("getter.method", property, bean));
            }

            try {
                if (labelProperty != null)
                    label = PropertyUtils.getProperty(bean, labelProperty);
                else
                    label = value;
                if (label == null)
                    label = "";
            } catch (IllegalAccessException e) {
                throw new JspException(messages.getMessage("getter.access", labelProperty, bean));
            } catch (InvocationTargetException e) {
                Throwable t = e.getTargetException();
                throw new JspException(messages.getMessage("getter.result", labelProperty, t.toString()));
            } catch (NoSuchMethodException e) {
                throw new JspException(messages.getMessage("getter.method", labelProperty, bean));
            }

            String stringValue = value.toString();
            boolean equal = false;
            try {
                equal = stringValue.equals(BeanUtil.getPropertyDefault(object, this.getProperty()));
            } catch (Exception e) {
            }
            addOption(sb, stringValue, label.toString(), equal);
        }

        // Render this element to our writer
        ResponseUtils.write(pageContext, sb.toString());

        // Evaluate the remainder of this page
        return EVAL_PAGE;

    }

    /**
     * Add an option element to the specified StringBuffer based on the
     * specified parameters.
     *
     * @param sb StringBuffer accumulating our results
     * @param value Value to be returned to the server for this option
     * @param label Value to be shown to the user for this option
     * @param matched Should this value be marked as selected?
     */
    protected void addOption(StringBuffer sb, String value, String label,
                             boolean matched) {
        if (this.isDisplayOnly()) {
            if (matched) {
                if (this.getShowCode()) {
                    sb.append(value);
                    if (this.getShowDescription()) {
                        sb.append(" - ");
                    }
                }
                if (this.getShowDescription()) {
                    sb.append(label);
                }
                sb.append("<input type=\"hidden\" name=\"").append(this.getProperty()).append("\" value=\"").append(ResponseUtils.filter(value)).append("\" />");
            }
        } else {
            sb.append("<option value=\"");
            sb.append(value);
            sb.append("\"");
            if (matched)
                sb.append(" selected=\"selected\"");
            if (this.getStyle() != null) {
                sb.append(" style=\"");
                sb.append(this.getStyle());
                sb.append("\"");
            }
            if (this.getStyleClass() != null) {
                sb.append(" class=\"");
                sb.append(this.getStyleClass());
                sb.append("\"");
            }
            sb.append(">");
            if (!CommonUtil.isEmpty(value) || !CommonUtil.isEmpty(label)) {
                if (this.getShowCode()) {
                    sb.append(value);
                    if (this.getShowDescription()) {
                        sb.append(" - ");
                    }
                }
                if (this.getShowDescription()) {
                    sb.append(ResponseUtils.filter(label));
                }
            }
            sb.append("</option>\r\n");
        }
    }

    /**
     * Return an iterator for the option labels or values, based on our
     * configured properties.
     *
     * @param name
     *            Name of the bean attribute (if any)
     * @param property
     *            Name of the bean property (if any)
     *
     * @exception JspException
     *                if an error occurs
     */
    protected Iterator getIterator(String name, String property) throws JspException {
        if (property == null) throw new JspException("property is null");
        return getIterator(name, !property.startsWith("srch") ? new String[] {
                property + "Values",
                property + "Values",
                BeanUtil.toPropertyName("srch", this.getProperty()) + "FrValues",
                BeanUtil.toPropertyName("srch", this.getProperty()) + "Values"
        } : new String[] {
                property + "Values",
                property + "Values"
        });
    }

    /**
     * Return an iterator for the option labels or values, based on our
     * configured properties.
     *
     * @param name
     *            Name of the bean attribute (if any)
     * @param property
     *            Name of the bean property (if any)
     *
     * @exception JspException
     *                if an error occurs
     */
    protected Iterator getIterator(String name, String[] properties) throws JspException {

        // Identify the bean containing our collection
        String beanName = name;
        if (beanName == null)
            beanName = Constants.BEAN_KEY;

        int i = 0;
        Object originalBean = null;
        for (;;) {
            Object bean = pageContext.findAttribute(beanName);
            if (bean == null)
                throw new JspException(messages.getMessage("getter.bean", beanName));
            // Identify the collection itself
            if (i == 0) originalBean = bean;
            Object collection = bean;
            String property = properties[i];
            if (property != null) {
                try {
                    collection = PropertyUtils.getProperty(bean, property);
                    if (collection == null)
                        throw new JspException(messages.getMessage("getter.property", property));
                    // Construct and return an appropriate iterator
                    if (collection.getClass().isArray())
                        collection = Arrays.asList((Object[]) collection);
                    if (collection instanceof Collection)
                        return (((Collection) collection).iterator());
                    else if (collection instanceof Iterator)
                        return ((Iterator) collection);
                    else if (collection instanceof Map)
                        return (((Map) collection).entrySet().iterator());
                    else if (collection instanceof Enumeration)
                        return (new IteratorAdapter((Enumeration) collection));
                    else
                        throw new JspException(messages.getMessage("optionsTag.iterator", collection.toString()));
                } catch (IllegalAccessException e) {
                    throw new JspException(messages.getMessage("getter.access", property, name));
                } catch (InvocationTargetException e) {
                    Throwable t = e.getTargetException();
                    throw new JspException(messages.getMessage("getter.result", property, t.toString()));
                } catch (NoSuchMethodException e) {
                    if (i == properties.length - 1) {
                        Map map = new LinkedMap();
                        map.put("ERROR", "Pls implement " + name + BeanUtil.toPropertyName(".get", properties[0]) + "().");
                        try {
                            BeanUtil.setPropertyDefault(originalBean, this.getProperty(), "ERROR");
                        } catch (Exception ex) {
                            Logger.logExceptions(originalBean, ex);
                        }
                        return map.entrySet().iterator();
                    }
                    if (!Constants.BEAN_KEY.equals(beanName)) {
                        beanName = Constants.BEAN_KEY;
                    }
                }
            }
            ++i;
        }
    }

    protected int doLabelStartTag(Object object, MetaData metadata) throws JspException {
        String voPropertyName = (metadata != null && !CommonUtil.isEmpty(metadata.getVoPropertyName())) ? "" + metadata.getVoPropertyName() + "" : "";
        String columnName = (metadata != null && !CommonUtil.isEmpty(metadata.getColumnName())) ? "" + metadata.getTableName() + "." + metadata.getColumnName() + "" : "";
        String titleContent = "";
        if (!CommonUtil.isEmpty(voPropertyName)) titleContent += "Property: " + voPropertyName;
        if (!CommonUtil.isEmpty(columnName)) titleContent += ((!CommonUtil.isEmpty(titleContent)) ? ", " : "") + "Column Name: " + columnName;
        String title = (!CommonUtil.isEmpty(titleContent)) ? "title=\"" + titleContent + "\"" : "";
        String output = (metadata != null && !metadata.isNullable()) ? "<span class=\"mandatory_label\" " + title + "><span class=\"mandatory_indicator\">*</span>" : "<span " + title +" >";
        String value = CommonUtil.nullToString((metadata != null) ? metadata.getWebLabelName() : this.getProperty());
        if (filter) value = ResponseUtils.filter(value);
        output += value;
        if (CommonUtil.isEmpty(this.getChildTsIndex())) {
            output += ": ";
            try {
                if (metadata != null && Date.class.isAssignableFrom(Class.forName(metadata.getColumnClassName()))) {
                    output += " " + SimpleConstants.WEB_FIELD_DATE_FORMAT_LABEL;
                }
            } catch (Exception e) {
            }
        }
        output += "</span>";
        ResponseUtils.write(pageContext, output);

        // Continue processing this page
        return (SKIP_BODY);
    }

    protected int doWriteStartTag(Object object, MetaData metadata) throws JspException {
        // Look up the requested property value
        boolean number = false;
        if (metadata != null) {
            try {
                Class propertyClass = Class.forName(metadata.getColumnClassName());
                number = Number.class.isAssignableFrom(propertyClass);
            } catch (ClassNotFoundException e) {
                Logger.log(metadata, e.getMessage());
            }
        }
        if (number) {
            if (metadata != null && metadata.isAmount() && this.getDecimalPlaces() < 0) this.setDecimalPlaces(2);
        }
        number = false; // temporialy turned off the number formatting feature
        Object value = RequestUtils.lookup(pageContext, name, property, null);
        if (number) ResponseUtils.write(pageContext, "<span style=\"width: 100%; text-align: right;\">");
        ResponseUtils.write(pageContext, "<input type=\"hidden\" " + (CommonUtil.isEmpty(this.getStyleId())?"":" id=\""+this.getStyleId()+"\" ") + " name=\"" + this.getProperty() + "\" value=\"" + ResponseUtils.filter(CommonUtil.getString(value)) + "\" />");

        // Print this property value to our output writer, suitably filtered
        String output = (metadata != null && metadata.isAutoGenerated() && WebUtil.isModeCreate(object)) ? SimpleConstants.WEB_FIELD_TO_BE_GENERATED : WebUtil.formatOutput(object, metadata, value, this.getDecimalPlaces());
        if (!this.isHidden() && value != null) {
            ResponseUtils.write(pageContext, (filter) ? ResponseUtils.filter(output) : output);
        }
        if (number) ResponseUtils.write(pageContext, "</span>");
        // Continue processing this page
        return (SKIP_BODY);
    }

    protected int doTextStartTag(Object object, MetaData metadata) throws JspException {
        boolean number = false;
        if (metadata != null) {
            try {
                Class propertyClass = Class.forName(metadata.getColumnClassName());
                number = Number.class.isAssignableFrom(propertyClass);
            } catch (ClassNotFoundException e) {
                Logger.log(metadata, e.getMessage());
            }
        }
        if (this.getDecimalPlaces() >= 0) {
            if (metadata != null && metadata.isAmount() && this.getDecimalPlaces() < 0) this.setDecimalPlaces(2);
            try {
                this.setValue(WebUtil.formatOutput(object, metadata, BeanUtil.getPropertyDefault(object, this.getProperty()), this.getDecimalPlaces()));
            } catch (RuntimeException e) {
            }
        }
        number = false; // temporialy turned off the number formatting feature
        int result = -1;
        boolean renderCalendar = false;
        boolean hideButton = false;
        if (this.isDisplayOnly() || (metadata != null && metadata.isAutoGenerated())) {
            result = this.doWriteStartTag(object, metadata);
        } else {
            try {
                if (metadata != null) renderCalendar = Date.class.isAssignableFrom(Class.forName(metadata.getColumnClassName()));
//                if (object instanceof SimpleCoreForm) {
//					SimpleCoreForm form = (SimpleCoreForm) pageContext.findAttribute(Constants.BEAN_KEY);
//					renderCalendar &= !WebUtil.isReadOnly(object, form);
//				} else if (object instanceof MultiRow) {
//                	hideButton = ((MultiRow) object).isDeleted();
//                }
                if(renderCalendar){
                	hideButton = this.getReadonly();
                	if (object instanceof MultiRow) {
                    	hideButton = hideButton || ((MultiRow) object).isDeleted();
                    }
                }
            } catch (Exception e) {
                Logger.debug(metadata, e);
            }
            if (renderCalendar) {
                //this.setDisabled(true);
            }
            if (number) this.setStyle("text-align: right;");
            String destPropety = property;
            if(showGuideInfo){
            	destPropety = renderGuideInfo(object, metadata);
            }
            
            result = super.doStartTag();
            
            if (renderCalendar) {
            	if(this.calendarImgFlag){
            		ResponseUtils.write(pageContext, "&nbsp;<span title=\"Date Calendar\"><img src=\""+this.calendarImgUrl+"\" style=\"cursor:pointer\" name=\""
							+ destPropety
							+ "Calendar\" onclick='doPopupCalendar(this, \""
							+ SimpleConstants.INPUT_DATE_FORMAT.toLowerCase()
							+ "\");' "+ (hideButton?" style=\"display:none;\"":" ") + " /></span>");
            	}else{
	                ResponseUtils.write(pageContext, "<input type=button name=\""
							+ destPropety
							+ "Calendar\" onclick='doPopupCalendar(this, \""
							+ SimpleConstants.INPUT_DATE_FORMAT.toLowerCase()
							+ "\")' value='...' class='button1'" + (hideButton?" style=\"display:none;\"":" ") + " />");
            	}
            }
        }
        return result;
    }

    protected String renderGuideInfo(Object object, MetaData metadata) throws JspException {
    	String guideInfo = CommonUtil.trim(ProjectConstants.UI_TYPE_GUIDE_INFO_PREFIX + metadata.getWebLabelName());
    	String hidObjectName = this.getProperty();
    	String idx = CommonUtil.getPropertyStrIdx(hidObjectName);
    	String hidObjectValue ="";
    	String hidObjectId = "";
    	
    	if(object instanceof MultiRow && CommonUtil.isEmpty(idx)){
    		hidObjectId = hidObjectName + ((MultiRow)object).getIdx();
    	}else{
    		hidObjectId = hidObjectName;
    	}
    	try {
    		if(CommonUtil.isEmpty(idx)){
    			hidObjectValue = CommonUtil.nullToString(CommonUtil.isEmpty(this.value) ? PropertyUtils
						.getSimpleProperty(object, hidObjectName) : this.value);
    		}else{
    			hidObjectValue = CommonUtil.nullToString(CommonUtil.isEmpty(this.value) ? PropertyUtils
						.getNestedProperty(object, hidObjectName) : this.value);
    		}
		} catch (Exception e) {
			e.printStackTrace();
		}
    	String focusStr = "objectFocus(window, event,'"+guideInfo+"')";
    	String blurStr = "objectBlur(window, event,'"+guideInfo+"','"+hidObjectId+"')";
    	
    	this.setValue(CommonUtil.isEmpty(hidObjectValue)?guideInfo:hidObjectValue);
    	this.setName("");
    	this.setProperty("");
    	this.setOnblur(blurStr);
    	this.setOnfocus(focusStr);
    	if(CommonUtil.isEmpty(hidObjectValue)){
    		this.setStyle("color:#676767;");	
    	}
    	ResponseUtils.write(pageContext,"<input type='hidden' id='"+
                hidObjectId+"' name='"+hidObjectName+"' value='"+CommonUtil.nullToString(ResponseUtils.filter(hidObjectValue))+"' />");
    	return hidObjectName;
    }
    
    protected int doTextareaStartTag(Object object, MetaData metadata) throws JspException {
        if (this.isDisplayOnly()) {
            //ResponseUtils.write(pageContext, "<pre>");
            int result = this.doWriteStartTag(object, metadata);
            //ResponseUtils.write(pageContext, "</pre>");
            return result;
        }
        String destPropety = property;
        if(showGuideInfo){
        	destPropety = renderGuideInfo(object, metadata);
        }
        // Create an appropriate "input" element based on our parameters
        StringBuffer results = new StringBuffer("<nobr><textarea");
        results.append(" name=\"");
        results.append(property);
        results.append("\"");
        if (accesskey != null) {
            results.append(" accesskey=\"");
            results.append(accesskey);
            results.append("\"");
        }
        if (tabindex != null) {
            results.append(" tabindex=\"");
            results.append(tabindex);
            results.append("\"");
        }
        if (cols != null) {
            results.append(" cols=\"");
            results.append(cols);
            results.append("\"");
        }
        if (rows != null) {
            results.append(" rows=\"");
            results.append(rows);
            results.append("\"");
        }
            results.append(prepareEventHandlers());
            results.append(prepareStyles());
        results.append(">");
        if (value != null) {
            results.append(ResponseUtils.filter(value));
        } else {
            Object bean = pageContext.findAttribute(name);
            if (bean == null)
            throw new JspException
                (messages.getMessage("getter.bean", name));
            try {
            String value = BeanUtils.getProperty(bean, property);
            if (value == null)
                value = "";
            results.append(ResponseUtils.filter((String) value));
            } catch (IllegalAccessException e) {
            throw new JspException
                (messages.getMessage("getter.access", property, name));
            } catch (InvocationTargetException e) {
            Throwable t = e.getTargetException();
            throw new JspException
                (messages.getMessage("getter.result",
                         property, t.toString()));
            } catch (NoSuchMethodException e) {
            throw new JspException
                (messages.getMessage("getter.method", property, name));
            }
        }
        results.append("</textarea>");
        
        results.append("<input type=\"button\" name=\"...\" value=\"...\" "
                + "class=\"button1\" onclick=\"" + this.toDoSubmitEventHandler(object, BeanUtil.toPropertyName(SimpleConstants.ACTION_SPEDIT, destPropety)) + "\"/></nobr>");
        // Print this field to our output writer
        ResponseUtils.write(pageContext, results.toString());

        // Continue processing this page
        return (EVAL_BODY_TAG);
    }

    public void release() {
        this.reset();
    }

    protected String toDoSubmitEventHandler(String pageEvent) {
        return toDoSubmitEventHandler(pageContext.findAttribute(this.getName()), pageEvent);
    }

    protected String toDoSubmitEventHandler(Object bean, String pageEvent) {
    	String pageEventSrc = (bean instanceof MultiRow) ? ", " + ((MultiRow) bean).getIdx() : ","+(CommonUtil.isEmpty(this.getIdx())? "''":"'"+this.getIdx()+"'");
        return "javascript:doSubmit('" + pageEvent + "'" + pageEventSrc + ");";
    }

    public boolean isShowCodeSet() {
        return showCodeSet;
    }

    public void setShowCodeSet(boolean showCodeSet) {
        this.showCodeSet = showCodeSet;
    }

	public boolean isCalendarImgFlag() {
		return calendarImgFlag;
	}

	public void setCalendarImgFlag(boolean calendarImgFlag) {
		this.calendarImgFlag = calendarImgFlag;
	}

	public String getCalendarImgUrl() {
		return calendarImgUrl;
	}

	public void setCalendarImgUrl(String calendarImgUrl) {
		this.calendarImgUrl = calendarImgUrl;
	}

}
